package com.sxt.jt808.dto;

import javax.annotation.Resource;

import org.springframework.stereotype.Component;

import com.sxt.jt808.util.BitConverter;

import cn.hutool.core.codec.BCD;
import io.netty.buffer.ByteBuf;
import io.netty.util.ReferenceCountUtil;

/**
 * @Author: 罗林
 * @Date: 2019-12-15
 * @Description:Jt808消息结构
 * @Version: 1.0
 */
@Component//让springboot在初始化的时候能扫描到
public abstract class Jt808Msg {
	
	
	//注意，@Autowired ,@Resource都无法注入
	private BitConverter bitConverter = new BitConverter();
	
	/**
	 * 消息头 12byte
	 */
	private MsgHeader msgHeader;

	/**
	 * 消息体ByteBuf(方便后期采用ByteBuf计算)
	 */
	private ByteBuf msgBodyByteBuf;
	/**
	 * 消息体字节数组
	 */
	private byte[] msgBodyBytes;
	
	/**
	 * 消息体
	 */
	private ByteBuf msgByteBuf;
	/**
	 * 校验码 1byte
	 */
	private int checkSum;

	// TODO set 和 get 方法
	public MsgHeader getMsgHeader() {
		return msgHeader;
	}

	public void setMsgHeader(MsgHeader msgHeader) {
		this.msgHeader = msgHeader;
	}

	public ByteBuf getMsgByteBuf() {
		return msgByteBuf;
	}

	public void setMsgByteBuf(ByteBuf msgByteBuf) {
		this.msgByteBuf = msgByteBuf;
	}

	public int getCheckSum() {
		return checkSum;
	}

	public void setCheckSum(int checkSum) {
		this.checkSum = checkSum;
	}

	public byte[] getMsgBodyBytes() {
		return msgBodyBytes;
	}

	public void setMsgBodyBytes(byte[] msgBodyBytes) {
		this.msgBodyBytes = msgBodyBytes;
	}
//	public BitConverter getBitConverter() {
//		return bitConverter;
//	}
//
//	public void setBitConverter(BitConverter bitConverter) {
//		this.bitConverter = bitConverter;
//	}
	public ByteBuf getMsgBodyByteBuf() {
		return msgBodyByteBuf;
	}

	public void setMsgBodyByteBuf(ByteBuf msgBodyByteBuf) {
		this.msgBodyByteBuf = msgBodyByteBuf;
	}

	
	//=================================分割线=================================//
	/**
	 * 无参构造函数
	 * 
	 * @param raw
	 * @return
	 */
	public Jt808Msg() {

	}

	/**
	 * 有参构造函数
	 * 
	 * @param byteBuf
	 * @return
	 */
	public Jt808Msg(ByteBuf byteBuf) {
		this.msgByteBuf = byteBuf;
		//this.setMsgByteBuf(byteBuf);
	}

	/**
	 * 
	 * 解析头消息和消息体信息
	 */
	public void parse() {
		try {
			this.parseHeader();// 报异常 null
			// 验证包体长度
			int msgBodyByteStartIndex = 12;
			// 2. 消息体
			// 有子包信息,消息体起始字节后移四个字节:消息包总数(word(16))+包序号(word(16))
			if (msgHeader.isHasSubPackage()) {
				msgBodyByteStartIndex = 16;
			}
			//解析消息体ByteBuf
//			ByteBuf header = byteBuf.slice(0, 5);
//		    ByteBuf body = byteBuf.slice(5, 10);
			//获取到 buf的不同区域的切片
			this.msgBodyByteBuf = this.msgByteBuf.slice(msgBodyByteStartIndex,msgHeader.getMsgBodyLength());
			
			//解析消息体字节数组
			byte[] tmp = this.msgBodyByteBuf.array();
			this.setMsgBodyBytes(tmp);
			
			//验证包体长度
            if (this.msgHeader.getMsgBodyLength() != this.msgBodyByteBuf.readableBytes()) {
                throw new RuntimeException("包体长度有误");
            }
			this.parseBody();
		} finally {
			// 释放
			ReferenceCountUtil.safeRelease(this.msgByteBuf);
		}
	}

	/**
	 * 解析头消息
	 */
	private void parseHeader() {
		//消息头,必须new
		MsgHeader header = new MsgHeader(); 

		header.setMsgId(this.msgByteBuf.getShort(0));// 消息体ID 2字节

		// ========消息体属性========
		int msgBodyProps = this.msgByteBuf.getShort(2);
		header.setMsgBodyPropsField(msgBodyProps);// byte[2-3] 2字节
		// [ 0-9 ] 0000,0011,1111,1111(3FF)(消息体长度)
		header.setMsgBodyLength(msgBodyProps & 0x1ff);// 消息体长度
		// [10-12] 0001,1100,0000,0000(1C00)(加密类型)
		header.setEncryptionType((msgBodyProps & 0xe00) >> 10);// 数据加密方式
		// [ 13_ ] 0010,0000,0000,0000(2000)(是否有子包)
		header.setHasSubPackage(((msgBodyProps & 0x2000) >> 13) == 1);// 是否分包
		header.setReservedBit(((msgBodyProps & 0xc000) >> 14) + "");// 保留位[14-15]

		// =====消息包封装项========
		if (header.isHasSubPackage()) {
			header.setPackageInfoField(this.msgByteBuf.getInt(12));// 消息包封装项字段
			header.setTotalSubPackage(this.msgByteBuf.getShort(12));// 消息包总数(word(16))
			header.setSubPackageSeq(this.msgByteBuf.getShort(14));// 包序号(word(16))这次发送的这个消息包是分包中的第几个消息包, 从 1 开始
		}
		
		// 终端手机号 6字节
		byte[] bytes = new byte[6];
		msgByteBuf.getBytes(4, bytes);
		header.setTerminalPhone(BCD.bcdToStr(bytes)); //
		System.out.println(this.bitConverter.bcd2String(bytes));
		
		// 消息流水号 2字节
		header.setFlowId(this.msgByteBuf.getShort(10));
		
		this.setMsgHeader(header);
	}
	
	
	
	/**
	 * 消息体信息，子类请求报文重写
	 */
	protected abstract void parseBody();

}
